﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpShare.Storage.Searching.Parameters;

namespace SharpShare.Storage.Searching {
    public class TreeStorageSearchEngine : IStorageSearchEngine {
        public TreeStorageSearchEngine(IStorageContainer rootContainer) {
            this.Container = rootContainer;
        }

        public bool SearchConcurrently { get; set; }

        #region IStorageSearchEngine Members

        public IStorageContainer Container {
            get;
            private set;
        }

        public IEnumerable<IStorageItem> Search(SearchParameter parameter) {
            IEnumerable<IStorageItem> results;

            if (SearchConcurrently) {
                results = SearchContainerConcurrent(this.Container, parameter);
            } else {
                results = SearchContainer(this.Container, parameter);
            }

            return results;
        }

        #endregion

        private IEnumerable<IStorageItem> SearchContainer(IStorageContainer container, SearchParameter parameter) {
            foreach (IStorageItem child in container.Contents) {
                if (parameter.Matches(child)) {
                    yield return child;
                }

                IStorageContainer childContainer = child.AsContainer();

                if (childContainer != null) {
                    foreach (var childResult in SearchContainer(childContainer, parameter)) {
                        yield return childResult;
                    }
                }
            }
        }

        private IEnumerable<IStorageItem> SearchContainerConcurrent(IStorageContainer container, SearchParameter parameter) {
            List<Task<IEnumerable<IStorageItem>>> childContainerTasks = new List<Task<IEnumerable<IStorageItem>>>();

            foreach (IStorageItem child in container.Contents) {
                if (parameter.Matches(child)) {
                    yield return child;
                }

                IStorageContainer childContainer = child.AsContainer();

                if (childContainer != null) {
                    Task<IEnumerable<IStorageItem>> task =
                    Task<IEnumerable<IStorageItem>>.Factory.StartNew(() => {
                        return SearchContainerConcurrent(childContainer, parameter).ToList();
                    });

                    childContainerTasks.Add(task);
                }
            }

            Task.WaitAll(childContainerTasks.ToArray());

            var childContainerResults = childContainerTasks
                .SelectMany(t => t.Result);

            foreach (var childResult in childContainerResults) {
                yield return childResult;
            }
        }
    }
}
